home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 6 / CU Amiga Magazine's Super CD-ROM 06 (1996)(EMAP Images)(GB)(Track 1 of 4)[!][issue 1997-01].iso / cucd / magazine / executive_v2.00 / data / developers.lzx / ExecutiveAPI / Example.c < prev    next >
C/C++ Source or Header  |  2001-10-06  |  10KB  |  489 lines

  1. /*
  2.  * ExecutiveAPI example
  3.  *
  4.  * This file is public domain.
  5.  *
  6.  * Author: Petri Nordlund <petrin@megabaud.fi>
  7.  *
  8.  * $Id: Example.c 1.1 1996/10/01 23:06:09 petrin Exp petrin $
  9.  *
  10.  */
  11.  
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #include <exec/ports.h>
  15. #include <dos/dos.h>
  16. #include <dos/dostags.h>
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23.  
  24. #include "ExecutiveAPI.h"
  25.  
  26. #ifdef __SASC
  27. #include <dos.h>
  28. #define GETA4() geta4()
  29. #else /* GCC */
  30. #define GETA4() ix_geta4()
  31. #endif
  32.  
  33. #define STACK_SIZE 10000L
  34.  
  35. void MyExit(void);
  36. BOOL SendMessage(struct ExecutiveMessage *msg);
  37. void WatchMe(void);
  38. void WatchMe_entry(void);
  39. void WatchRelative(void);
  40. void WatchRelative_entry(void);
  41.  
  42. struct ExecutiveMessage *msg = NULL;
  43. struct Task *parent_task;
  44. BYTE parent_signal;
  45. WORD active_tasks = 0;
  46.  
  47.  
  48. /**
  49.  ** This is an example on how to use ExecutiveAPI. All ExecutiveAPI features
  50.  ** are demonstrated.
  51.  **
  52.  **/
  53.  
  54. int
  55. main(int argc, char **argv)
  56. {
  57.     LONG oldnice;
  58.  
  59.     atexit(MyExit);
  60.  
  61. /**
  62.  ** Allocate ExecutiveMessage structure and initialize it.
  63.  **
  64.  **/
  65.  
  66.     if(!(msg=AllocVec(sizeof(struct ExecutiveMessage), MEMF_PUBLIC|MEMF_CLEAR)))
  67.     {
  68.         puts("Can't allocate ExecutiveMessage structure.");
  69.         exit(RETURN_FAIL);
  70.     }
  71.  
  72.     if(!(msg->message.mn_ReplyPort=CreateMsgPort()))
  73.     {
  74.         puts("Can't create message port.");
  75.         exit(RETURN_FAIL);
  76.     }
  77.  
  78.     msg->message.mn_Node.ln_Type = NT_MESSAGE;
  79.     msg->message.mn_Length       = sizeof(struct ExecutiveMessage);
  80.  
  81.     /** Make sure this is always initialized to zero! **/
  82.     msg->ident = 0;
  83.  
  84. /**
  85.  ** Add this program as Executive client. Executive can't quit
  86.  ** before all clients have been removed.
  87.  **
  88.  **/
  89.  
  90.     msg->command = EXAPI_CMD_ADD_CLIENT;
  91.  
  92.     if(!SendMessage(msg))
  93.     {
  94.         puts("Can't add new client.");
  95.         exit(RETURN_FAIL);
  96.     }
  97.  
  98. /**
  99.  ** Ask Executive to return the real (not the scheduling) priority of this
  100.  ** task. If this task is currently scheduled and you read the priority
  101.  ** directly from task-structure, it will be somewhere in the dynamic
  102.  ** range. There's no GetTaskPri() routine in exec.library which could
  103.  ** be patched to return the real priority.
  104.  **
  105.  ** In a case a new task is launched with its parent task's priority, which
  106.  ** is in the dynamic range, Executive notices this, and sets the real
  107.  ** priority of the new task to its parent task's real priority. But if
  108.  ** wish to create a childtask whose priority will be the priority of the 
  109.  ** parent task plus one, and you read the priority from task-structure, it
  110.  ** might be something like -58. Add one to this value, and you'll get -57.
  111.  ** Executive can't correct this, so in this case use the
  112.  ** EXAPI_CMD_GET_PRIORITY command to obtain task's real priority.
  113.  **
  114.  **/
  115.  
  116.     msg->command = EXAPI_CMD_GET_PRIORITY;
  117.     msg->task    = FindTask(NULL);
  118.  
  119.     if(!SendMessage(msg))
  120.     {
  121.         puts("Can't obtain this task's real priority.");
  122.         exit(RETURN_FAIL);
  123.     }
  124.  
  125.     printf("Scheduling priority: %d --- Real priority: %d\n",
  126.             FindTask(NULL)->tc_Node.ln_Pri,
  127.             msg->value1);
  128.  
  129. /**
  130.  ** Set this task's nice-value to -10. Store old value and restore it later.
  131.  ** You should restore the nice-value, if the program can be executed in a
  132.  ** shell, as the shell process will then get the nice-value.
  133.  **
  134.  **/
  135.  
  136.     msg->command = EXAPI_CMD_SET_NICE;
  137.     msg->task    = FindTask(NULL);
  138.     msg->value1  = -10;                        /* new nice-value */
  139.  
  140.     if(!SendMessage(msg))
  141.     {
  142.         puts("Can't set this task's nice-value.");
  143.         exit(RETURN_FAIL);
  144.     }
  145.  
  146.     oldnice = msg->value1;
  147.  
  148.     printf("Old nice-value: %d\n",oldnice);
  149.  
  150. /**
  151.  ** Get current nice-value.
  152.  **
  153.  **/
  154.  
  155.     msg->command = EXAPI_CMD_GET_NICE;
  156.     msg->task    = FindTask(NULL);
  157.  
  158.     if(!SendMessage(msg))
  159.     {
  160.         puts("Can't obtain this task's nice-value.");
  161.         exit(RETURN_FAIL);
  162.     }
  163.  
  164.     printf("Current nice-value: %d\n",msg->value1);
  165.  
  166. /**
  167.  ** Restore old nice-value.
  168.  **
  169.  **/
  170.  
  171.     msg->command = EXAPI_CMD_SET_NICE;
  172.     msg->task    = FindTask(NULL);
  173.     msg->value1  = oldnice;
  174.  
  175.     if(!SendMessage(msg))
  176.     {
  177.         puts("Can't set this task's nice-value.");
  178.         exit(RETURN_FAIL);
  179.     }
  180.  
  181. /**
  182.  ** Two EXAPI_CMD_WATCH examples.
  183.  **
  184.  **/
  185.  
  186.     WatchMe();
  187.     Delay(2*50);
  188.     WatchRelative();
  189.  
  190. /**
  191.  ** Client is removed in MyExit(). Don't forget to do it.
  192.  **
  193.  **/
  194.  
  195.     return(RETURN_OK);
  196. }
  197.  
  198.  
  199.  
  200. void
  201. MyExit(void)
  202. {
  203.  
  204. /**
  205.  ** Remove the client. This can't fail.
  206.  **
  207.  **/
  208.  
  209.     if(msg && (msg->message.mn_ReplyPort))
  210.     {
  211.         msg->command = EXAPI_CMD_REM_CLIENT;
  212.  
  213.         SendMessage(msg);
  214.     }
  215.  
  216. /**
  217.  ** Delete the message.
  218.  **
  219.  **/
  220.  
  221.     if(msg)
  222.     {
  223.         if(msg->message.mn_ReplyPort)
  224.             DeleteMsgPort(msg->message.mn_ReplyPort);
  225.  
  226.         FreeVec(msg);
  227.     }
  228. }
  229.  
  230.  
  231.  
  232. /**
  233.  ** Send message to Executive's public message port.
  234.  ** Return TRUE if success, FALSE if error occurred.
  235.  ** See msg->error for the specific error code.
  236.  **
  237.  **/
  238. BOOL
  239. SendMessage(struct ExecutiveMessage *message)
  240. {
  241.     struct MsgPort *port;
  242.  
  243. /**
  244.  ** Find Executive public message port and send the message.
  245.  ** Wait for reply.
  246.  **
  247.  **/
  248.  
  249.     Forbid();
  250.  
  251.     if(port=FindPort(EXECUTIVEAPI_PORTNAME))
  252.     {
  253.         PutMsg(port, (struct Message *) message);
  254.         Permit();
  255.         WaitPort(message->message.mn_ReplyPort);
  256.         while(GetMsg(message->message.mn_ReplyPort))
  257.             ;
  258.         if(!message->error)
  259.             return(TRUE);
  260.     }
  261.     else
  262.     {
  263.         /** Executive is not running **/
  264.         Permit();
  265.     }
  266.  
  267.     return(FALSE);
  268. }
  269.  
  270.  
  271. /**
  272.  ** Create a new task. The new task will send a message to Executive and ask
  273.  ** that its priority is kept below all scheduled tasks. This is like having
  274.  ** the following entry in Executive.prefs:
  275.  **
  276.  **   TASK  Example_childtask NOSCHEDULE  BELOW
  277.  **
  278.  ** Start the Top client and you'll se what happens to the childtask's
  279.  ** priority.
  280.  **
  281.  **/
  282.  
  283. void
  284. WatchMe(void)
  285. {
  286.     if((parent_signal=AllocSignal(-1)) != -1)
  287.     {
  288.         parent_task = FindTask(NULL);
  289.  
  290.         if(CreateNewProcTags(    NP_Entry,        (ULONG) WatchMe_entry,
  291.                                 NP_Name,        (ULONG) "Example_childtask",
  292.                                 NP_Priority,    0,
  293.                                 NP_StackSize,    STACK_SIZE,
  294.                                 TAG_DONE))
  295.         {
  296.             puts("Childtask started. Wait...");
  297.             Wait(1L << parent_signal);
  298.             puts("Childtask finished.");
  299.         }
  300.         else
  301.         {
  302.             FreeSignal(parent_signal);
  303.             puts("Can't create new process.");
  304.             exit(RETURN_FAIL);
  305.         }
  306.  
  307.         FreeSignal(parent_signal);
  308.     }
  309.     else
  310.     {
  311.         puts("Can't allocate signal.");
  312.         exit(RETURN_FAIL);
  313.     }
  314. }
  315.  
  316. void
  317. WatchMe_entry(void)
  318. {
  319.     struct ExecutiveMessage *message;
  320.     int t,i;
  321.  
  322.     /** This routine needs DosBase, parent_task and parent_signal **/
  323.     GETA4();
  324.  
  325.     if(message=AllocVec(sizeof(struct ExecutiveMessage), MEMF_PUBLIC|MEMF_CLEAR))
  326.     {
  327.         if(message->message.mn_ReplyPort=CreateMsgPort())
  328.         {
  329.             message->message.mn_Node.ln_Type = NT_MESSAGE;
  330.             message->message.mn_Length       = sizeof(struct ExecutiveMessage);
  331.  
  332.             /** Make sure this is always initialized to zero! **/
  333.             message->ident = 0;
  334.  
  335.             message->command = EXAPI_CMD_WATCH;
  336.             message->task    = FindTask(NULL);
  337.             message->value1  = EXAPI_WHICH_TASK;
  338.             message->value2  = EXAPI_TYPE_NOSCHEDULE;
  339.             message->value3  = EXAPI_PRI_BELOW;
  340.  
  341.             /** Ignore error **/
  342.             SendMessage(message);
  343.         }
  344.     }
  345.  
  346.     /** Use some CPU time **/
  347.     for(t=0;t<20;t++)
  348.     {
  349.         for(i=0;i<1000000;i++)
  350.             ;
  351.         Delay(30);
  352.     }
  353.  
  354.     if(message)
  355.     {
  356.         if(message->message.mn_ReplyPort)
  357.             DeleteMsgPort(message->message.mn_ReplyPort);
  358.  
  359.         FreeVec(message);
  360.     }
  361.  
  362.     /** Forbid so we can finish completely, before the parent cleans up. **/
  363.     Forbid();
  364.  
  365.     Signal(parent_task, 1L << parent_signal);
  366. }
  367.  
  368.  
  369. /**
  370.  ** Create three tasks with priorities -1, 0 and +1. Assume that this task's
  371.  ** priority is 0. Configure Executive to schedule all childtasks of this
  372.  ** task so that their priority is relative to this task's priority. This is
  373.  ** like having the following entry in Executive.prefs:
  374.  **
  375.  **   CHILDTASKS  Example  RELATIVE
  376.  **
  377.  ** Start the Top client and you'll se what happens to childtask priorities.
  378.  ** Try using the PGRP option with Ps: "ps PGRP=<this task's pid>". You'll
  379.  ** see that the childtasks don't seem to use any CPU time. CPU usage is
  380.  ** transferred to the parent task, because its CPU usage is used when
  381.  ** scheduling priority is calculated.
  382.  **
  383.  ** IMPORTANT! You'll have to issue the WATCH-command BEFORE starting any
  384.  ** childtasks!
  385.  **
  386.  **/
  387.  
  388. void
  389. WatchRelative(void)
  390. {
  391.     msg->command = EXAPI_CMD_WATCH;
  392.     msg->task    = FindTask(NULL);
  393.     msg->value1  = EXAPI_WHICH_CHILDTASKS;
  394.     msg->value2  = EXAPI_TYPE_RELATIVE;
  395.  
  396.     if(!SendMessage(msg))
  397.     {
  398.         puts("EXAPI_CMD_WATCH command failed.");
  399.         if(msg->error == EXAPI_ERROR_ALREADY_WATCHED)
  400.         {
  401.             puts("You can only issue an EXAPI_CMD_WATCH command once for each task.");
  402.             puts("Executive remembers the task name, and if that task is started again,");
  403.             puts("it knows what to do with it.");
  404.             puts("If EXAPI_CMD_WATCH fails, check for EXAPI_ERROR_ALREADY_WATCHED");
  405.             puts("in msg->error. You can safely ignore this error. It's also possible");
  406.             puts("that user has put the task to Executive.prefs.");
  407.         }
  408.         else
  409.             exit(RETURN_FAIL);
  410.     }
  411.  
  412.     if((parent_signal=AllocSignal(-1)) != -1)
  413.     {
  414.         struct Process *proc1, *proc2, *proc3;
  415.  
  416.         parent_task = FindTask(NULL);
  417.  
  418.         /** Forbid so all tasks start to run at the same time **/
  419.         Forbid();
  420.  
  421.         proc1 = CreateNewProcTags(NP_Entry,    (ULONG) WatchRelative_entry,
  422.                       NP_Name,    (ULONG) "Example_childtask1",
  423.                       NP_Priority,    -1,
  424.                       NP_StackSize,    STACK_SIZE,
  425.                       TAG_DONE);
  426.         proc2 = CreateNewProcTags(NP_Entry,    (ULONG) WatchRelative_entry,
  427.                       NP_Name,    (ULONG) "Example_childtask2",
  428.                       NP_Priority,    0,
  429.                       NP_StackSize,    STACK_SIZE,
  430.                       TAG_DONE);
  431.         proc3 = CreateNewProcTags(NP_Entry,    (ULONG) WatchRelative_entry,
  432.                       NP_Name,    (ULONG) "Example_childtask3",
  433.                       NP_Priority,    1,
  434.                       NP_StackSize,    STACK_SIZE,
  435.                       TAG_DONE);
  436.         Permit();
  437.  
  438.         if(proc1)    active_tasks++;
  439.         if(proc2)    active_tasks++;
  440.         if(proc3)    active_tasks++;
  441.  
  442.         if(active_tasks)
  443.         {
  444.             puts("Childtasks started. Wait...");
  445.             do {
  446.                 Wait(1L << parent_signal);
  447.             } while(active_tasks);
  448.             puts("Childtasks finished.");
  449.         }
  450.         else
  451.         {
  452.             FreeSignal(parent_signal);
  453.             puts("Can't create new process.");
  454.             exit(RETURN_FAIL);
  455.         }
  456.  
  457.         FreeSignal(parent_signal);
  458.     }
  459.     else
  460.     {
  461.         puts("Can't allocate signal.");
  462.         exit(RETURN_FAIL);
  463.     }
  464. }
  465.  
  466. void
  467. WatchRelative_entry(void)
  468. {
  469.     int t,i;
  470.  
  471.     /** We need DosBase, parent_task, parent_signal and active_tasks **/
  472.     GETA4();
  473.  
  474.     /** Use some CPU time **/
  475.     for(t=0;t<20;t++)
  476.     {
  477.         for(i=0;i<350000;i++)
  478.             ;
  479.         Delay(40);
  480.     }
  481.  
  482.     /** Forbid so we can finish completely, before the parent cleans up. **/
  483.     Forbid();
  484.  
  485.     active_tasks--;
  486.  
  487.     Signal(parent_task, 1L << parent_signal);
  488. }
  489.